package Juego;

import java.util.ArrayList;
import java.util.Observable;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import Construibles.Construible;
import Construibles.EstBomberos;
import Construibles.ZonaResidencial;
import Desastres.Godzilla;
import Desastres.Terremoto;
import Excepciones.DineroInsuficiente;
import Excepciones.FueraDeLimites;
import Excepciones.SuperficieNoValida;
import MapaStuff.Hectarea;
import MapaStuff.Mapa;
import RedStuff.ClienteAgua;
import RedStuff.ClienteElectrico;
import RedStuff.ClienteVial;
import RedStuff.ConectorAgua;
import RedStuff.ConectorElectrico;
import RedStuff.ConectorVial;
import RedStuff.FuenteAgua;
import RedStuff.FuenteElectrica;
import RedStuff.FuenteVial;
import RedStuff.RedAgua;
import RedStuff.RedElectrica;
import RedStuff.RedVial;
import Ubicacion.Punto;

public class Jugador extends Observable implements SerializablePropia{
	
	private int turnos;
	private int dinero;
	public Mapa mapaDelJuego;	
	private Poblacion poblacion;
	private ArrayList<EstBomberos> bomberos;
	private RedElectrica redElectrica=new RedElectrica();
	private RedAgua redAgua=new RedAgua();
	private RedVial redVial=new RedVial();
	private Godzilla godzilla;
	private Terremoto terremoto;
	
	public Jugador() {
		turnos =0;
		dinero = 10000;
		mapaDelJuego = Mapa.nuevoMapa();
		poblacion = new Poblacion();
		bomberos = new ArrayList<EstBomberos>();
		godzilla = new Godzilla();
		terremoto = new Terremoto();
		setChanged();
		this.notifyObservers();
	}
	
	public void descontarDinero(int dineroADescontar) throws DineroInsuficiente{
		if (dinero>=dineroADescontar){
			dinero = dinero - dineroADescontar;
		}
		else{
			throw new DineroInsuficiente();
		}
		setChanged();
		notifyObservers();
			
	}
	
	public void ponerConstruibleEn (Construible construible, Punto punto) throws DineroInsuficiente, SuperficieNoValida{
		Hectarea unaHectarea;
		try {
			unaHectarea = mapaDelJuego.darHectarea(punto);
			if(unaHectarea.contenido()!=null){
				unaHectarea.contenido().desconectarseRedes(this);
			}
			unaHectarea.construir(construible);
			construible.descontarDinero(this);
			construible.agregarseARedes(this);
			
		} catch (FueraDeLimites e) {
			// No puede ser fuera de limites
		}
					
	}

	public int dineroDisponible() {
		return dinero;
	}
	
	public void cobrarImpuestos(){
		dinero = dinero + poblacion.pagarImpuestos();
	}

	public void agregarBombero(EstBomberos estBomberos) {
		bomberos.add(estBomberos);		
	}
	
	public void pasarTurno (){
		turnos ++;
		redElectrica.suministrar();
		redAgua.suministrar();
		redVial.suministrar();
		poblacion.crecer();
		terremoto.pasarTemblor();
		if (!godzilla.estaDormido()){
			godzilla.mover();
		}
		if (turnos%30==0)this.cobrarImpuestos();
		
		if (turnos%3==0){
			for (EstBomberos bomberoActual : bomberos){
				bomberoActual.repararMapa(mapaDelJuego);
			}
		}
		
		setChanged();
		notifyObservers();
		
	}

	public void agregarARedElectrica(ConectorElectrico conector){
		this.redElectrica.agregarConector(conector);
	}
	
	public void removerDeRedElectrica(ConectorElectrico conector){
		this.redElectrica.removerConector(conector);
	}
	
	public void removerDeRedElectrica(FuenteElectrica fuente){
		this.redElectrica.removerFuente(fuente);
	}
	public void agregarARedElectrica(FuenteElectrica fuente){
		this.redElectrica.agregarFuente(fuente);
	}
	public void agregarARedElectrica(ClienteElectrico cliente){
		this.redElectrica.agregarCliente(cliente);
	}
	public void removerDeRedElectrica(ClienteElectrico cliente){
		this.redElectrica.removerCliente(cliente);
	}
	
	public void agregarARedVial(ClienteVial cliente){
		this.redVial.agregarCliente(cliente);
	}
	
	public void removerDeRedVial(ClienteVial cliente){
		this.redVial.removerCliente(cliente);
	}
	
	public void agregarARedVial(FuenteVial fuente){
		this.redVial.agregarFuente(fuente);
	}
	
	public void removerDeRedVial(FuenteVial fuente){
		this.redVial.removerFuente(fuente);
	}
	
	public void agregarARedVial(ConectorVial conector){
		this.redVial.agregarConector(conector);
	}
	public void removerDeRedVial(ConectorVial conector){
		this.redVial.removerConector(conector);
	}
	
	public void agregarARedAgua(FuenteAgua fuente){
		this.redAgua.agregarFuente(fuente);
	}
	
	public void removerDeRedAgua(FuenteAgua fuente){
		this.redAgua.removerFuente(fuente);
	}
	
	public void agregarARedAgua(ConectorAgua conector){
		this.redAgua.agregarConector(conector);
	}
	
	public void removerDeRedAgua(ConectorAgua conector){
		this.redAgua.removerConector(conector);
	}
	
	public void agregarARedAgua(ClienteAgua cliente){
		this.redAgua.agregarCliente(cliente);
	}
	public void removerDeRedAgua(ClienteAgua cliente){
		this.redAgua.removerCliente(cliente);
	}
	
	
	
	public Poblacion poblacion(){
		return poblacion;
	}
	
	public void agregarAPobalcion(ZonaResidencial zona){
		poblacion.agregarResidencia(zona);
	}

	public void despertarGodzilla() {
		if (godzilla.estaDormido()){
			godzilla.despertar();	
		}
	}
	
	public Godzilla godzilla(){
		return godzilla;
	}
	
	public Terremoto terremoto(){
		return terremoto;
	}

	public void crearTerremoto() {
		try {
			Punto unPunto = Punto.puntoAlAzar();
			terremoto.crearSismoEn(unPunto);
		} catch (FueraDeLimites e) {
			// no puede ser fuera de limite
		}
		
	}
	
	public Element serializar(Document doc){
		Element eleJugador=doc.createElement("Jugador");
		eleJugador.setAttribute("dinero", Integer.toString(dinero));
		eleJugador.setAttribute("turnos", Integer.toString(turnos));
		eleJugador.appendChild(mapaDelJuego.serializar(doc));
		eleJugador.appendChild(poblacion.serializar(doc));
		eleJugador.appendChild(redElectrica.serializar(doc));
		eleJugador.appendChild(redAgua.serializar(doc));
		eleJugador.appendChild(redVial.serializar(doc));
		eleJugador.appendChild(godzilla.serializar(doc));
		Element eleBomberos=doc.createElement("Bomberos");
		eleJugador.appendChild(eleBomberos);
		SerializadorPorUbicacionEnElMapa.serializarPorUbicacionEnElMapa(eleBomberos, doc, bomberos);
		return eleJugador;
		
	}
	
	private static class AgregadorDeJugador implements Agregador{

		private Jugador jug;
		public AgregadorDeJugador(Jugador jug){
			this.jug=jug;
		}
		public void agregar(SerializablePropia elemento) {
			jug.agregarBombero ((EstBomberos)elemento);
		}	
	}
	
	public static Jugador hidratar(Document doc){
		Jugador jug=new Jugador();
		Element eleJugador= (Element) doc.getElementsByTagName("Jugador").item(0);
		jug.dinero=Integer.parseInt(eleJugador.getAttribute("dinero"));
		jug.turnos=Integer.parseInt(eleJugador.getAttribute("turnos"));
		jug.mapaDelJuego=Mapa.hidratar(eleJugador.getChildNodes().item(0));
		jug.poblacion=Poblacion.hidratar(eleJugador.getChildNodes().item(1));
		jug.redElectrica=RedElectrica.hidratar(eleJugador.getChildNodes().item(2));
		jug.redAgua=RedAgua.hidratar(eleJugador.getChildNodes().item(3));
		jug.redVial=RedVial.hidratar(eleJugador.getChildNodes().item(4));
		jug.godzilla=Godzilla.hidratar(eleJugador.getChildNodes().item(5));
		Element bomberos= (Element) doc.getElementsByTagName("Bomberos").item(0);
		Agregador agregador=(Agregador)new AgregadorDeJugador(jug);
		SerializadorPorUbicacionEnElMapa.hidratarPorUbicacionEnElMapa(bomberos,agregador);
		return jug;
	}

	public void eliminarBombero(EstBomberos estBomberos) {
		
		while(bomberos.remove(estBomberos));
	}

	public void eliminarDePoblacion(ZonaResidencial zona){
		poblacion.eliminarZona(zona);
	}

}
